package ru.ifmo.swing.genetics;

import org.uncommons.watchmaker.swing.NumericParameterControl;
import ru.ifmo.swing.Panel;
import ru.ifmo.swing.RunButton;
import ru.ifmo.swing.genetics.monitoring.string.StringInfoMonitor;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author avhaliullin
 */
public class MultiLaunchController implements ProcessFinishedListener {
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy-HH.mm.ss");

    private final ControlConfigParamsFetcher paramsFetcher;
    private final RunButton runButton;
    private final StringInfoMonitor stringInfoMonitor;

    private final Panel control;
    private final NumericParameterControl<Integer> launchesControl;
    private final JButton launchButton;
    private final JButton stopButton;

    private int counter;
    private int limit;
    private long startTimestamp;
    private String workDir;
    private volatile boolean launched = false;

    private int minMinStatesCount;
    private int maxMinStatesCount;
    private double averageMinStatesCount;
    private int bestDFWordsCount;
    private int minMinWordLength;
    private int maxMinWordLength;
    private double averageMinWordLength;
    private int minSuperGenerationNumber;
    private int maxSuperGenerationNumber;
    private double averageSuperGenerationNumber;

    public MultiLaunchController(ControlConfigParamsFetcher paramsFetcher, RunButton runButton, StringInfoMonitor stringInfoMonitor) {
        this.paramsFetcher = paramsFetcher;
        this.runButton = runButton;
        this.stringInfoMonitor = stringInfoMonitor;

        control = new Panel();
        control.setHorizontal(true);
        launchesControl = new NumericParameterControl<Integer>(1, Integer.MAX_VALUE, 1, 20);

        control.add(launchesControl.getControl());

        launchButton = new JButton("Launch");
        stopButton = new JButton("Stop");
        stopButton.setEnabled(false);
        launchButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                doRun();
            }
        });
        stopButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                doStop();
            }
        });
        control.add(launchButton);
        control.add(stopButton);
    }

    private void doRun() {
        launchButton.setEnabled(false);
        stopButton.setEnabled(true);
        launched = true;
        limit = launchesControl.getNumberGenerator().nextValue();
        counter = 0;
        minMinStatesCount = Integer.MAX_VALUE;
        maxMinStatesCount = 0;
        averageMinStatesCount = 0;
        /*workDir = DATE_FORMAT.format(new Date());
        File dir = new File(workDir);
        if (!dir.mkdir()) {
            throw new RuntimeException("Failed to create directory " + workDir);
        }
        try {
            PrintWriter writer = new PrintWriter(new FileWriter(workDir + "/" + "config.txt"));
            writer.print(paramsFetcher.fetchParams());
            writer.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }*/
        launch();
    }

    private void launch() {
        startTimestamp = System.currentTimeMillis();
        runButton.doRun();
    }

    private void doStop() {
        launchButton.setEnabled(true);
        stopButton.setEnabled(false);
        launched = false;
        try {
            PrintWriter writer = new PrintWriter(new FileWriter(DATE_FORMAT.format(new Date()) + "_result.txt"));
            writer.println(paramsFetcher.fetchParams());
            writer.println(counter + " launches");
            writer.println("min |MSW| = " + minMinWordLength);
            writer.println("max |MSW| = " + maxMinWordLength);
            writer.println("ave |MSW| = " + averageMinWordLength / bestDFWordsCount);
            writer.println("min |Q.w| = " + minMinStatesCount);
            writer.println("max |Q.w| = " + maxMinStatesCount);
            writer.println("ave |Q.w| = " + averageMinStatesCount / counter);
            writer.println("min first generation = " + minSuperGenerationNumber);
            writer.println("max first generation = " + maxSuperGenerationNumber);
            writer.println("ave first generation = " + averageSuperGenerationNumber / bestDFWordsCount);
            writer.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void finished() {
        if (launched) {
            /*String results = stringInfoMonitor.getStringView();
            long deltaTime = System.currentTimeMillis() - startTimestamp;
            try {
                PrintWriter writer = new PrintWriter(new FileWriter(String.format("%1$s/launch%2$03d.txt", workDir, counter)));
                writer.println(results);
                writer.print("Time elapsed: " + deltaTime + " milliseconds");
                writer.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }*/
            if (stringInfoMonitor.getMinStatesCount() < minMinStatesCount) {
                minMinStatesCount = stringInfoMonitor.getMinStatesCount();
                bestDFWordsCount = 1;
                minMinWordLength = stringInfoMonitor.getMinWordLength();
                maxMinWordLength = stringInfoMonitor.getMinWordLength();
                averageMinWordLength = stringInfoMonitor.getMinWordLength();
                minSuperGenerationNumber = stringInfoMonitor.getSuperGenerationNumber();
                maxSuperGenerationNumber = stringInfoMonitor.getSuperGenerationNumber();
                averageSuperGenerationNumber = stringInfoMonitor.getSuperGenerationNumber();
            } else if (stringInfoMonitor.getMinStatesCount() == minMinStatesCount) {
                bestDFWordsCount++;
                minMinWordLength = Math.min(minMinWordLength, stringInfoMonitor.getMinWordLength());
                maxMinWordLength = Math.max(maxMinWordLength, stringInfoMonitor.getMinWordLength());
                averageMinWordLength += stringInfoMonitor.getMinWordLength();
                minSuperGenerationNumber = Math.min(minSuperGenerationNumber, stringInfoMonitor.getSuperGenerationNumber());
                maxSuperGenerationNumber = Math.max(maxSuperGenerationNumber, stringInfoMonitor.getSuperGenerationNumber());
                averageSuperGenerationNumber += stringInfoMonitor.getSuperGenerationNumber();
            }
            minMinStatesCount = Math.min(minMinStatesCount, stringInfoMonitor.getMinStatesCount());
            maxMinStatesCount = Math.max(maxMinStatesCount, stringInfoMonitor.getMinStatesCount());
            averageMinStatesCount += stringInfoMonitor.getMinStatesCount();
            counter++;
            System.err.println(counter);
            if (counter >= limit) {
                doStop();
            } else {
                launch();
            }
        }
    }

    public JComponent getControl() {
        return control;
    }
}
